🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / app / src / main / java / com / geeksville / mesh / service / PacketHandler.kt
Displaying Raw • Download
app/src/main/java/com/geeksville/mesh/service/PacketHandler.kt 1c3784235e7e20ed88e054097d2e7addbff92dc3 (1c378423) Text, 8.04 KB
T8b949e/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787com.geeksville.mesh.service
Tff7b72import T7ee787com.geeksville.mesh.concurrent.handledLaunch
Tff7b72import T7ee787com.geeksville.mesh.repository.radio.RadioInterfaceService
Tff7b72import T7ee787dagger.Lazy
Tff7b72import T7ee787java8.util.concurrent.CompletableFuture
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.Dispatchers
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787org.meshtastic.core.data.repository.MeshLogRepository
Tff7b72import T7ee787org.meshtastic.core.data.repository.PacketRepository
Tff7b72import T7ee787org.meshtastic.core.database.entity.MeshLog
Tff7b72import T7ee787org.meshtastic.core.model.DataPacket
Tff7b72import T7ee787org.meshtastic.core.model.MessageStatus
Tff7b72import T7ee787org.meshtastic.core.model.util.toOneLineString
Tff7b72import T7ee787org.meshtastic.core.model.util.toPIIString
Tff7b72import T7ee787org.meshtastic.core.service.ConnectionState
Tff7b72import T7ee787org.meshtastic.proto.MeshProtos
Tff7b72import T7ee787org.meshtastic.proto.MeshProtos.MeshPacket
Tff7b72import T7ee787org.meshtastic.proto.MeshProtos.ToRadio
Tff7b72import T7ee787org.meshtastic.proto.fromRadio
Tff7b72import T7ee787timber.log.Timber
Tff7b72import T7ee787java.util.UUID
Tff7b72import T7ee787java.util.concurrent.ConcurrentLinkedQueue
Tff7b72import T7ee787java.util.concurrent.TimeUnit
Tff7b72import T7ee787java.util.concurrent.TimeoutException
Tff7b72import T7ee787javax.inject.Inject
Tff7b72import T7ee787javax.inject.Singleton
Tf0883e@Singleton
Tff7b72class T56d364PacketHandler
Tf0883e@Inject
Tff7b72constructorTb4b4b4(
Tff7b72private Tff7b72val Te6edf3packetRepositoryTb4b4b4: Te6edf3LazyTff7b72<Te6edf3PacketRepositoryTff7b72>Tb4b4b4,
Tff7b72private Tff7b72val Te6edf3serviceBroadcastsTb4b4b4: Te6edf3MeshServiceBroadcastsTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioInterfaceServiceTb4b4b4: Te6edf3RadioInterfaceServiceTb4b4b4,
Tff7b72private Tff7b72val Te6edf3meshLogRepositoryTb4b4b4: Te6edf3LazyTff7b72<Te6edf3MeshLogRepositoryTff7b72>Tb4b4b4,
Tff7b72private Tff7b72val Te6edf3connectionStateHolderTb4b4b4: Te6edf3MeshServiceConnectionStateHolderTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72private Tff7b72const Tff7b72val Te6edf3TIMEOUT_MS Tff7b72= T79c0ff2T79c0ff5T79c0ff0L
Tb4b4b4}
Tff7b72private Tff7b72var Te6edf3queueJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72val Te6edf3scope Tff7b72= Te6edf3CoroutineScopeTb4b4b4(Te6edf3DispatchersTb4b4b4.Te6edf3IOTb4b4b4)
Tff7b72private Tff7b72val Te6edf3queuedPackets Tff7b72= Te6edf3ConcurrentLinkedQueueTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3queueResponse Tff7b72= Te6edf3mutableMapOfTff7b72<Tffa657IntTb4b4b4, Te6edf3CompletableFutureTff7b72<Tffa657BooleanTff7b72>Tff7b72>Tb4b4b4(Tb4b4b4)
T8b949e/**
* Send a command/packet to our radio. But cope with the possibility that we might start up before we are fully
* bound to the RadioInterfaceService
*/
Tff7b72fun Td2a8ffsendToRadioTb4b4b4(Te6edf3pTb4b4b4: Te6edf3ToRadioTb4b4b4.Te6edf3BuilderTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3built Tff7b72= Te6edf3pTb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffSending to radio Tffd700${Te6edf3builtTb4b4b4.Te6edf3toPIIStringTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72val Te6edf3b Tff7b72= Te6edf3builtTb4b4b4.Te6edf3toByteArrayTb4b4b4(Tb4b4b4)
Te6edf3radioInterfaceServiceTb4b4b4.Te6edf3sendToRadioTb4b4b4(Te6edf3bTb4b4b4)
Te6edf3changeStatusTb4b4b4(Te6edf3pTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3idTb4b4b4, Te6edf3MessageStatusTb4b4b4.Te6edf3ENROUTETb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3hasDecodedTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3packetToSave Tff7b72=
Te6edf3MeshLogTb4b4b4(
Te6edf3uuid Tff7b72= Te6edf3UUIDTb4b4b4.Te6edf3randomUUIDTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3message_type Tff7b72= Ta5d6ff"Ta5d6ffPacketTa5d6ff"Tb4b4b4,
Te6edf3received_date Tff7b72= Te6edf3SystemTb4b4b4.Te6edf3currentTimeMillisTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3raw_message Tff7b72= Te6edf3pTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3fromNum Tff7b72= Te6edf3pTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3fromTb4b4b4,
Te6edf3portNum Tff7b72= Te6edf3pTb4b4b4.Te6edf3packetTb4b4b4.Te6edf3decodedTb4b4b4.Te6edf3portnumValueTb4b4b4,
Te6edf3fromRadio Tff7b72= Te6edf3fromRadio Tb4b4b4{ Te6edf3packet Tff7b72= Te6edf3pTb4b4b4.Te6edf3packet Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3insertMeshLogTb4b4b4(Te6edf3packetToSaveTb4b4b4)
Tb4b4b4}
Tb4b4b4}
T8b949e/**
* Send a mesh packet to the radio, if the radio is not currently connected this function will throw
* NotConnectedException
*/
Tff7b72fun Td2a8ffsendToRadioTb4b4b4(Te6edf3packetTb4b4b4: Te6edf3MeshPacketTb4b4b4) Tb4b4b4{
Te6edf3queuedPacketsTb4b4b4.Te6edf3addTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3startPacketQueueTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffstopPacketQueueTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3queueJobTff7b72?.Te6edf3isActive Tff7b72=Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3iTb4b4b4(Ta5d6ff"Ta5d6ffStopping packet queueJobTa5d6ff"Tb4b4b4)
Te6edf3queueJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3queueJob Tff7b72= Tff7b72null
Te6edf3queuedPacketsTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Te6edf3queueResponseTb4b4b4.Te6edf3entriesTb4b4b4.Te6edf3lastOrNull Tb4b4b4{ Tff7b72!Tffa657itTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3isDone Tb4b4b4}Tff7b72?.Te6edf3valueTff7b72?.Te6edf3completeTb4b4b4(Tff7b72falseTb4b4b4)
Te6edf3queueResponseTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffhandleQueueStatusTb4b4b4(Te6edf3queueStatusTb4b4b4: Te6edf3MeshProtosTb4b4b4.Te6edf3QueueStatusTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ff[queueStatus] Tffd700${Te6edf3queueStatusTb4b4b4.Te6edf3toOneLineStringTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72val Tb4b4b4(Te6edf3successTb4b4b4, Te6edf3isFullTb4b4b4, Te6edf3requestIdTb4b4b4) Tff7b72= Te6edf3withTb4b4b4(Te6edf3queueStatusTb4b4b4) Tb4b4b4{ Te6edf3TripleTb4b4b4(Te6edf3res Tff7b72=Tff7b72= T79c0ff0Tb4b4b4, Te6edf3free Tff7b72=Tff7b72= T79c0ff0Tb4b4b4, Te6edf3meshPacketIdTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3success Tff7b72&Tff7b72& Te6edf3isFullTb4b4b4) Tff7b72return T8b949e// Queue is full, wait for free != 0
Tff7b72if Tb4b4b4(Te6edf3requestId Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3queueResponseTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3requestIdTb4b4b4)Tff7b72?.Te6edf3completeTb4b4b4(Te6edf3successTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3queueResponseTb4b4b4.Te6edf3entriesTb4b4b4.Te6edf3lastOrNull Tb4b4b4{ Tff7b72!Tffa657itTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3isDone Tb4b4b4}Tff7b72?.Te6edf3valueTff7b72?.Te6edf3completeTb4b4b4(Te6edf3successTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffremoveResponseTb4b4b4(Te6edf3dataRequestIdTb4b4b4: Tffa657IntTb4b4b4, Te6edf3completeTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Te6edf3queueResponseTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3dataRequestIdTb4b4b4)Tff7b72?.Te6edf3completeTb4b4b4(Te6edf3completeTb4b4b4)
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffSwallowedExceptionTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffstartPacketQueueTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3queueJobTff7b72?.Te6edf3isActive Tff7b72=Tff7b72= Tff7b72trueTb4b4b4) Tff7b72return
Te6edf3queueJob Tff7b72=
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffpacket queueJob startedTa5d6ff"Tb4b4b4)
Tff7b72while Tb4b4b4(Te6edf3connectionStateHolderTb4b4b4.Te6edf3connectionStateTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4) Tb4b4b4{
T8b949e// take the first packet from the queue head
Tff7b72val Te6edf3packet Tff7b72= Te6edf3queuedPacketsTb4b4b4.Te6edf3pollTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72break
Tff7b72try Tb4b4b4{
T8b949e// send packet to the radio and wait for response
Tff7b72val Te6edf3response Tff7b72= Te6edf3sendPacketTb4b4b4(Te6edf3packetTb4b4b4)
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffqueueJob packet id=Tffd700${Te6edf3packetTb4b4b4.Te6edf3idTb4b4b4.Te6edf3toUIntTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff waitingTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3success Tff7b72= Te6edf3responseTb4b4b4.Te6edf3getTb4b4b4(Te6edf3TIMEOUT_MSTb4b4b4, Te6edf3TimeUnitTb4b4b4.Te6edf3MILLISECONDSTb4b4b4)
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffqueueJob packet id=Tffd700${Te6edf3packetTb4b4b4.Te6edf3idTb4b4b4.Te6edf3toUIntTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff success Tffd700$Te6edf3successTa5d6ff"Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3TimeoutExceptionTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffqueueJob packet id=Tffd700${Te6edf3packetTb4b4b4.Te6edf3idTb4b4b4.Te6edf3toUIntTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff timeoutTa5d6ff"Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3dTb4b4b4(Ta5d6ff"Ta5d6ffqueueJob packet id=Tffd700${Te6edf3packetTb4b4b4.Te6edf3idTb4b4b4.Te6edf3toUIntTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff failedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e/** Change the status on a DataPacket and update watchers */
Tff7b72private Tff7b72fun Td2a8ffchangeStatusTb4b4b4(Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4, Te6edf3mTb4b4b4: Te6edf3MessageStatusTb4b4b4) Tff7b72= Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3packetId Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3getDataPacketByIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3p Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3status Tff7b72=Tff7b72= Te6edf3mTb4b4b4) Tff7b72returnTf0883e@handledLaunch
Te6edf3packetRepositoryTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3updateMessageStatusTb4b4b4(Te6edf3pTb4b4b4, Te6edf3mTb4b4b4)
Te6edf3serviceBroadcastsTb4b4b4.Te6edf3broadcastMessageStatusTb4b4b4(Te6edf3packetIdTb4b4b4, Te6edf3mTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMagicNumberTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffgetDataPacketByIdTb4b4b4(Te6edf3packetIdTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3DataPacket? Tff7b72= Te6edf3withTimeoutOrNullTb4b4b4(T79c0ff1T79c0ff0T79c0ff0T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3dataPacketTb4b4b4: Te6edf3DataPacket? Tff7b72= Tff7b72null
Tff7b72while Tb4b4b4(Te6edf3dataPacket Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3dataPacket Tff7b72= Te6edf3packetRepositoryTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3getPacketByIdTb4b4b4(Te6edf3packetIdTb4b4b4)Tff7b72?.Te6edf3data
Tff7b72if Tb4b4b4(Te6edf3dataPacket Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Te6edf3delayTb4b4b4(T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)
Tb4b4b4}
Te6edf3dataPacket
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffsendPacketTb4b4b4(Te6edf3packetTb4b4b4: Te6edf3MeshPacketTb4b4b4)Tb4b4b4: Te6edf3CompletableFutureTff7b72<Tffa657BooleanTff7b72> Tb4b4b4{
T8b949e// send the packet to the radio and return a CompletableFuture that will be completed with
T8b949e// the result
Tff7b72val Te6edf3future Tff7b72= Te6edf3CompletableFutureTff7b72<Tffa657BooleanTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3queueResponseTff7b72[Te6edf3packetTb4b4b4.Te6edf3idTff7b72] Tff7b72= Te6edf3future
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3connectionStateHolderTb4b4b4.Te6edf3connectionStateTb4b4b4.Te6edf3value Tff7b72!Tff7b72= Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3RadioNotConnectedExceptionTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3sendToRadioTb4b4b4(Te6edf3ToRadioTb4b4b4.Te6edf3newBuilderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{ Tff7b72thisTb4b4b4.Te6edf3packet Tff7b72= Te6edf3packet Tb4b4b4}Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3exTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3TimberTb4b4b4.Te6edf3eTb4b4b4(Te6edf3exTb4b4b4, Ta5d6ff"Ta5d6ffsendToRadio error: Tffd700${Te6edf3exTb4b4b4.Te6edf3messageTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3futureTb4b4b4.Te6edf3completeTb4b4b4(Tff7b72falseTb4b4b4)
Tb4b4b4}
Tff7b72return Te6edf3future
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffinsertMeshLogTb4b4b4(Te6edf3packetToSaveTb4b4b4: Te6edf3MeshLogTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
T8b949e// Do not log, because might contain PII
T8b949e// info("insert: ${packetToSave.message_type} =
T8b949e// ${packetToSave.raw_message.toOneLineString()}")
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3insertTb4b4b4(Te6edf3packetToSaveTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.09s